/*
 * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 * 
**/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMovie>
#include <QFile>
#include <QSpacerItem>
#include <QKeyEvent>
#include <QPainterPath>
#include <QDir>
#include <QFont>
#include <QPainter>
#include <QPixmap>
#include <QFontMetrics>
#include <QtMath>
#include <QAbstractItemView>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <libintl.h>
#include <locale.h>
#include "bioauthwidget.h"
#include <QHBoxLayout>
#include <QAction>
#include "generic.h"
#include "biotypes.h"
#include "modeButton.h"
#include <QDebug>
#define _(string) gettext(string)
extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed);

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    users(new Users(this)),
    enableBioAuth(false),
    receiveBioPAM(false),
    authMode(UNDEFINED),
    useDoubleAuth(false),
    m_timer(nullptr),
    isLockingFlg(false),
    m_nCurLockMin(0),
    isbioSuccess(false),
    useFirstDevice(false)
{
    ui->setupUi(this);
    setWindowTitle(tr("Authentication"));
    setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);

    pam_tally_init(); //

//    headerLayout = new QHBoxLayout();
//    headerLayout->setContentsMargins(8,0,8,0);
//    headerLayout->setSpacing(8);
//    logoLabel = new QLabel();
//    logoLabel->setPixmap(QIcon::fromTheme("ukui-polkit").pixmap(QSize(24,24)));
//    headerLayout->addWidget(logoLabel);
//    titleLabel = new QLabel();
//    titleLabel->setText(tr("Authenticate"));
//    headerLayout->addWidget(titleLabel);
//    ui->headerWidget->setLayout(headerLayout);
//    headerLayout->addStretch();
//    closeBtn = new QPushButton();
//    closeBtn->setFixedSize(30, 30);
//    closeBtn->setToolTip(tr("Close"));
//    closeBtn->setProperty("isWindowButton", 0x02);
//    closeBtn->setProperty("useIconHighlightEffect", 0x08);
//    closeBtn->setFlat(true);
//    closeBtn->setIcon(QIcon::fromTheme("window-close-symbolic"));
//    connect(closeBtn, &QPushButton::clicked, this, &MainWindow::close);
//    headerLayout->addWidget(closeBtn);

    // 登录选项
    m_labelTip = new QLabel();
    m_labelTip->setText("");
    m_labelTip->hide();
    m_loginOptsWidget = new LoginOptionsWidget();
    m_loginOptsWidget->hide();
    ui->titleTipLayout->addWidget(m_labelTip);
    ui->loginOptionsLayout->setAlignment(Qt::AlignTop|Qt::AlignHCenter);
    ui->loginOptionsLayout->addWidget(m_loginOptsWidget);

    maxFailedTimes = bioDevices.getFailedTimes();
    isHiddenSwitchButton = bioDevices.GetHiddenSwitchButton();
    useFirstDevice = bioDevices.getUseFirstDevice();

    connect(m_loginOptsWidget, &LoginOptionsWidget::optionSelected,
            this, [&](unsigned uCurLoginOptType, const DeviceInfoPtr &deviceInfo){
        qDebug() << "device changed: " << deviceInfo->biotype;
        if(m_failMap[getUid(userName)][deviceInfo->device_id] >= maxFailedTimes){
            qDebug() << "Failed MAX!!";
            return ;
        }
        if (deviceInfo == m_deviceInfo) {
            return;
        }
        m_deviceInfo = deviceInfo;
        switchLoginOptType(uCurLoginOptType);
        if(!isbioSuccess) {
            startBioAuth();
        }
    });

    connect(m_loginOptsWidget, &LoginOptionsWidget::notifyOptionsChange,
            this, [&](unsigned uOptionsCount){
        if (uOptionsCount > 0) {
            m_loginOptsWidget->show();
        } else {
            m_loginOptsWidget->hide();
        }
        if (!m_deviceInfo || !m_loginOptsWidget->findDeviceById(m_deviceInfo->device_id)
            || m_loginOptsWidget->isDeviceDisable(m_deviceInfo->device_id)) {
            m_loginOptsWidget->stopAuth();
            if (authMode != UNDEFINED) {
                authMode = UNDEFINED;
                emit switchToBiometric();
            }
        }
    });

    connect(m_loginOptsWidget, &LoginOptionsWidget::authComplete,
            this, [&](uid_t uid, bool ret, int nStatus){
        qDebug() << "biometric authentication complete: " << uid << ret << nStatus;

        if(uid == getUid(userName) && ret) {
            isbioSuccess = true;
            emit switchToBiometric();
            authMode = UNDEFINED;
        } else {
            if (nStatus >= 2) {
                if (m_deviceInfo) {
                    uid_t curUid = getUid(userName);
                    if(m_failMap.contains(curUid) && m_failMap[curUid].contains(m_deviceInfo->device_id)){
                        m_failMap[curUid][m_deviceInfo->device_id] = m_failMap[curUid][m_deviceInfo->device_id] + 1;
                    }else{
                        m_failMap[curUid][m_deviceInfo->device_id] = 1;
                    }
                    qDebug()<<"Failed count:"<<m_failMap[curUid][m_deviceInfo->device_id]<<",Max:"<<maxFailedTimes;
                    if (m_deviceInfo->biotype == BIOTYPE_FACE) {
                        QImage imgFailed;
                        m_loginOptsWidget->setFaceImg(imgFailed, 1);
                    }
                    if(m_failMap[curUid][m_deviceInfo->device_id] >= maxFailedTimes){
                        if (m_deviceInfo->biotype == REMOTE_QRCODE_TYPE) {
                            setLoginTypeTip(tr("Failed to verify %1, please enter password to unlock").arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype)));
                            QImage nullImage;
                            m_loginOptsWidget->setQRCode(nullImage);
                        } else {
                            setLoginTypeTip(tr("Unable to verify %1, please enter password to unlock").arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype)));
                        }
                        m_loginOptsWidget->setDeviceDisable(m_deviceInfo->device_id, true);
                        useDoubleAuth = false;
                        return ;
                    }
                    setLoginTypeTip(tr("Failed to verify %1, you still have %2 verification opportunities")
                       .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype))
                       .arg(maxFailedTimes-m_failMap[curUid][m_deviceInfo->device_id]));
                }
            }
            if(!isbioSuccess) {
                // dbus error
                if (nStatus == -1) {
                    qDebug()<<"Biometric dbus error:"<<authMode;
                }
                if (m_uCurLoginOptType == LOGINOPT_TYPE_QRCODE && nStatus == 1) {
                    m_isNetworkErr = true;
                    m_loginOptsWidget->setQRCodeMsg(tr("NET Exception"));
                    startBioAuth(10000);
                } else {
                    startBioAuth();
                }
                if (nStatus >= 2 && m_deviceInfo) {
                    if (m_deviceInfo->biotype == BIOTYPE_FACE) {
                        QImage imgFailed;
                        m_loginOptsWidget->setFaceImg(imgFailed, 1);
                    }
                }
            }
        }
    });

    connect(m_loginOptsWidget, &LoginOptionsWidget::updateAuthMsg, this, &MainWindow::onUpdateBioAuthMsg);
    connect(m_loginOptsWidget, &LoginOptionsWidget::updateWndSize, this, &MainWindow::onUpdateWndSize);

    QFile qssFile(":/qss/src/main.qss");
    qssFile.open(QIODevice::ReadOnly);
    setStyleSheet(qssFile.readAll());
    qssFile.close();

    //ui->cmbUsers->hide();
    //ui->widgetDetails->hide();
    //ui->btnDetails->setIcon(QIcon(":/image/assets/arrow_right.svg"));
    //ui->btnDetails->hide();
    ui->lePassword->installEventFilter(this);
    switchWidget(UNDEFINED);
    editIcon();
    ui->lblContent->adjustSize();
    ui->lblContent->height();
    ui->lblMessage->adjustSize();
    ui->widgetPasswdAuth->adjustSize();
    ui->lblMessage->height();
    ui->cmbUsers->view()->setTextElideMode(Qt::ElideRight);

    settings = new QGSettings("org.ukui.style","",this);
    fontSize  = settings->get("system-font-size").toInt();
    connect(settings, &QGSettings::changed,
            this, &MainWindow::onConfigurationChanged);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onConfigurationChanged(QString key)
{
    if(key == "systemFontSize"){
        m_loginOptsWidget->updateUIStatus(false);
        fontSize  = settings->get("system-font-size").toInt();
    }
    if(key == "iconThemeName") {
        setIcon(app_IconName);
    }
}

void MainWindow::restart_bio_identify()
{
    DeviceInfoPtr device = bioDevices.getDefaultDevice(getuid());
    if(device){
        m_loginOptsWidget->startAuth(device, getUid(userName));
        setMessage(tr("Please enter your password or enroll your fingerprint "));
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    m_loginOptsWidget->stopAuth();
    m_failMap.clear();
    emit canceled();

    return QWidget::closeEvent(event);
}

void MainWindow::paintEvent(QPaintEvent *event)
{

    Q_UNUSED(event);
    QStyleOption *option = new QStyleOption();
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    QPainterPath rectPath;
    rectPath.addRoundedRect(this->rect().adjusted(0,0,0,0),0,0);
    // 画一个黑底
    QPixmap pixmap(this->rect().size());
    pixmap.fill(Qt::transparent);
    QPainter pixmapPainter(&pixmap);
    pixmapPainter.setRenderHint(QPainter::Antialiasing);
    pixmapPainter.setPen(Qt::transparent);
    pixmapPainter.setBrush(QColor(0,0,0,100));
    pixmapPainter.drawPath(rectPath);
    pixmapPainter.end();

    // 模糊这个黑底
    QImage img = pixmap.toImage();
    qt_blurImage(img, 10, false, false);

    // 挖掉中心
    pixmap = QPixmap::fromImage(img);
    QPainter pixmapPainter2(&pixmap);
    pixmapPainter2.setRenderHint(QPainter::Antialiasing);
    pixmapPainter2.setCompositionMode(QPainter::CompositionMode_Clear);
    pixmapPainter2.setPen(Qt::transparent);
    pixmapPainter2.setBrush(Qt::transparent);
    pixmapPainter2.drawPath(rectPath);

    // 绘制阴影
    p.drawPixmap(this->rect(), pixmap, pixmap.rect());

    // 绘制一个背景
    p.save();
    p.fillPath(rectPath,option->palette.color(QPalette::Base));
    p.restore();
    //绘制一个矩形

    p.setPen(Qt::red);
    QRectF rect(0,290,20,20);

}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if(obj == ui->lePassword){
        if(event->type() == QEvent::KeyPress){ //禁止复制粘贴功能。
            QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
            if(keyEvent->matches(QKeySequence::Copy) || keyEvent->matches(QKeySequence::Cut) || keyEvent->matches(QKeySequence::Paste)){
                event->ignore();
                return true;
            }
        }
    }
    return false;
}

/*** main ***/
void MainWindow::on_cmbUsers_currentTextChanged(const QString &userName)
{
    qDebug() << "user changed to " << userName;
    m_loginOptsWidget->stopAuth();
    if(m_bioTimer && m_bioTimer->isActive())
        m_bioTimer->stop();
    authMode=UNDEFINED;

    QList<UserItem> accountUsers = users->getUsers();
    this->userName = userName;
    for(UserItem user:accountUsers){
        if(user.realName == userName){
            this->userName = user.name;
        }
    }

    m_deviceInfo = DeviceInfoPtr();
    ui->lblMessage->clear();
    ui->lblMessage->setToolTip("");
    isLockingFlg = false;
    emit userChanged(this->userName);
}

int MainWindow::enable_biometric_authentication()
{
    char conf_file[] = GET_STR(CONFIG_FILE);
    FILE *file;
    char line[1024], is_enable[16];
    int i;


    if((file = fopen(conf_file, "r")) == NULL){
        return 0;
    }
    while(fgets(line, sizeof(line), file)) {
        i = sscanf(line, "EnableAuth=%s\n",  is_enable);
        if(i > 0) {
            break;
        }
    }

    fclose(file);
    if(!strcmp(is_enable, "true"))
        return 1;
    return 0;
}

void MainWindow::on_btnDetails_clicked()
{/*
    if(ui->widgetDetails->isHidden()) {
        ui->widgetDetails->show();
        ui->btnDetails->setIcon(QIcon(":/image/assets/arrow_down.svg"));
//        resize(width(), height() + ui->widgetDetails->height());
    }
    else {
        ui->widgetDetails->hide();
        ui->btnDetails->setIcon(QIcon(":/image/assets/arrow_right.svg"));
//        resize(width(), height() - ui->widgetDetails->height());
    }
    adjustSize();*/
}

void MainWindow::on_btnCancel_clicked()
{
    close();
}

void MainWindow::on_btnAuth_clicked()
{
    on_lePassword_returnPressed();
}

/*** pagePassword ***/
void MainWindow::editIcon()
{
    m_modeButton = new ModeButton(ui->lePassword);
    m_modeButton->setFocusPolicy(Qt::NoFocus);
    connect(m_modeButton, &QPushButton::clicked, this, [=](){
        if (ui->lePassword->echoMode() == QLineEdit::Password) {
            ui->lePassword->setEchoMode(QLineEdit::Normal);
        } else {
            ui->lePassword->setEchoMode(QLineEdit::Password);
        }
    });
    QHBoxLayout *layout = new QHBoxLayout(ui->lePassword);
    layout->addStretch();
    layout->addWidget(m_modeButton);
    layout->setContentsMargins(0,0,8,0);

    ui->lePassword->setTextMargins(1, 1, 4+ m_modeButton->width(), 1);
}

void MainWindow::on_lePassword_returnPressed()
{
    emit accept(ui->lePassword->text());
    ui->btnAuth->hide();
    // switchWidget(UNDEFINED);
    // setMessage(tr("in authentication, please wait..."));
}

void MainWindow::on_btnBioAuth_clicked()
{
    emit switchToBiometric();
    authMode = BIOMETRIC;
}

void MainWindow::on_returnButton_clicked()
{

    m_loginOptsWidget->stopAuth();
    accept(BIOMETRIC_IGNORE);

}
/*** end of control's slot ***/


/*** public member ***/

void MainWindow::setIcon(const QString &iconName)
{
//    QIcon::setThemeName("ukui-icon-theme");
    app_IconName = iconName;
    if(!QIcon::hasThemeIcon("ukui-polkit")) {
        QDir iconsDir("/usr/share/icons");
        auto themesList = iconsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
        qDebug() << themesList;
        for(auto theme : themesList) {
            QIcon::setThemeName(theme);
            if(QIcon::hasThemeIcon("ukui-polkit")) {
                qDebug() << theme << "has ukui-polkit icon";
                break;
            }
        }
    }
    QPixmap icon = QIcon::fromTheme("ukui-polkit").pixmap(64, 64);
    QPixmap actionIcon = QIcon::fromTheme(app_IconName).pixmap(32, 32);
    QPainter painter;

    painter.begin(&icon);
    QRect rect(32,
               32,
               32, 32);
    painter.drawPixmap(rect, actionIcon);
    painter.end();

    setWindowIcon(icon);
    //ui->lblIcon->setPixmap(icon);
}

void MainWindow::setHeader(const QString &text)
{
    ui->lblHeader->setText(text);
    ui->lblHeader->adjustSize();
    ui->lblHeader->height();
    ui->lblContent->setText(tr("A program is attempting to perform an action that requires privileges."
                               "It requires authorization to perform the action."));
    ui->lblContent->adjustSize();
}

void MainWindow::setUsers(const QStringList &usersList)
{
    if(usersList.isEmpty())
        return;

    if(usersList.size() == 1) {
        UserItem user = users->getUserByName(usersList.at(0));
        if(user.realName != ""){
            userName = user.realName;
        }else{
            userName = usersList.at(0);
        }
    }

    QList<UserItem> accountUsers = users->getUsers();
    for(QString identifyUser:usersList){
        bool isFoundAccount = false;
        for(UserItem user:accountUsers){
            if(identifyUser == user.name){
                if(user.realName != "")
                    ui->cmbUsers->addItem(user.realName);
                else
                    ui->cmbUsers->addItem(user.name);
                isFoundAccount = true;
                break;
            }
        }
        if (!isFoundAccount) {
            ui->cmbUsers->addItem(identifyUser);
        }
    }

    ui->cmbUsers->show();
    ui->cmbUsers->adjustSize();
    ui->cmbUsers->height();
}
/*
void MainWindow::setDetails(const QString &subPid, const QString &callerPid, const QString &actionId,
                            const QString &actionDesc, const QString vendorName,
                            const QString vendorUrl)
{
    ui->lblSubjectPid->setText(subPid);
    ui->lblCallerPid->setText(callerPid);
    ui->lblActionId->setText(actionId);
    ui->lblActionDesc->setText(actionDesc);
    QString vendor = QString("<a href=\"%1\">%2").arg(vendorUrl).arg(vendorName);
    ui->lblVendor->setText(vendor);
}
*/
void MainWindow::setPrompt(const QString &text, bool echo)
{
    QString prompt = text;

    if(text == "Input Password"){
        prompt = tr("Input Password");
    } else if (text == "Password: " || text == "Password:") {
        prompt = tr("Password: ");
    } else if (text == "_Password: ") {
        prompt = tr("_Password: ");
    } else if (text == "_Password:") {
        prompt = tr("_Password:");
    }
    if(!m_timer){
        m_timer = new QTimer(this);
        m_timer->setInterval(200);
        connect(m_timer, &QTimer::timeout, this, &MainWindow::unlock_countdown);
    }
    //qDebug() << "6666";
    m_timer->start();

    ui->lePassword->clear();
    ui->lePassword->setPlaceholderText(prompt);
    switchWidget(PASSWORD);
}

/*
    转换pam英文提示，目前转换的就3个翻译
    Authenticated failed, account locked!
    Authenticated failed, 1 login attemps left
    Account locked, 4 minutes left
*/
QString MainWindow::check_is_pam_message(QString text)
{
    setlocale(LC_ALL,"");
    bindtextdomain("Linux-PAM","/usr/share/locale");
    bind_textdomain_codeset("Linux-PAM","UTF-8");
    textdomain("Linux-PAM");
    char*  str;
    QString strTrans = "";
    QByteArray ba = text.toLatin1(); // must
    str=ba.data();

    int a,b;
    //兼容旧版本翻译，以及适配新版本翻译
    if(text.contains("attemps",Qt::CaseSensitive) && sscanf(str,"Authenticated failed, %d login attemps left",&a))
          sprintf(str,_("Authenticated failed, %d login attemps left"),a);
    else if(text.contains("attempts",Qt::CaseSensitive) && sscanf(str,"Authenticated failed, %d login attempts left",&a))
          sprintf(str,_("Authenticated failed, %d login attempts left"),a);
    else if(text.contains("attempt",Qt::CaseSensitive) && sscanf(str,"Authenticated failed, %d login attempt left",&a))
          sprintf(str,_("Authenticated failed, %d login attempt left"),a);
    else if(text.contains("days",Qt::CaseSensitive) && sscanf(str,"Account locked, %d days left",&a)){
        strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("days left");
        return strTrans;
    }
    else if(text.contains("hours",Qt::CaseSensitive) && sscanf(str,"Account locked, %d hours left",&a)){
        strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("hours left");
        return strTrans;
    }
    else if(text.contains("minutes",Qt::CaseSensitive) && sscanf(str,"Account locked, %d minutes left",&a)){
        strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("minutes left");
        return strTrans;
    }
    else if(text.contains("seconds",Qt::CaseSensitive) && sscanf(str,"Account locked, %d seconds left",&a)){
        strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("seconds left");
        return strTrans;
    }
    else{
        str = _(str);
    }
          
    qDebug()<<"str = "<<str;
    return QString(str);

}

void MainWindow::setMessage(const QString &text,situation situat)
{

    if(situat == ERROR){
        QPalette pe;
        pe.setColor(QPalette::WindowText,Qt::red);
        ui->lblMessage->setPalette(pe);
        ui->lePassword->setStyleSheet("QLineEdit{background-color: palette(Button);"
                                      "lineedit-password-character:42;border-radius: 6px;border: 1px solid #F3222D;}");
    }else if(situat == TRUE){
       QColor color = palette().color(QPalette::WindowText);
       QPalette pal(this->palette());
       pal.setColor(QPalette::WindowText,QColor(color));
        ui->lblMessage->setPalette(pal);
    }

    // qDebug()<<"receive：text = "<<text;
    if (text.indexOf("account locked") != -1 || text.indexOf("账户已锁定") != -1 
        || text.indexOf("Account locked") != -1 || text.indexOf("永久锁定") != -1)
    {
        if(!m_timer){
            m_timer = new QTimer(this);
            m_timer->setInterval(800);
            connect(m_timer, &QTimer::timeout, this, &MainWindow::unlock_countdown);
        }
        m_timer->start();
    }else if (text.indexOf("No password received, please input password") != -1)
    {
        ui->lblMessage->setText(tr("Password cannot be empty"));
        ui->lblMessage->setToolTip(tr("Password cannot be empty"));
    }else{
        ui->lblMessage->setText(text);
        ui->lblMessage->setToolTip(text);
    }
    ui->lblMessage->adjustSize();
    ui->widgetPasswdAuth->adjustSize();
    // ui->lblMessage->setText(text);
}

void MainWindow::setAuthResult(bool result, const QString &text)
{
    QString message = text;

    if(!result && text.isEmpty()){
        message = tr("Authentication failed, please try again.");
    }

    if(authMode == PASSWORD)
        setMessage(message,ERROR);
    else if(authMode == BIOMETRIC)
        setMessage(message,ERROR);

    switchWidget(PASSWORD);
}

void MainWindow::clearEdit()
{
    ui->lePassword->setText("");
}

void MainWindow::switchAuthMode(Mode mode)
{
    if(isbioSuccess){
        accept(BIOMETRIC_SUCCESS);
        return ;
    }
    int uid = getUid(userName);
    m_loginOptsWidget->setUser(uid);
    int count = m_loginOptsWidget->getLoginOptCount();
    enableBioAuth  = count > 0;
    if (count < 1) {
        m_loginOptsWidget->hide();
    } else {
        m_loginOptsWidget->show();
        m_loginOptsWidget->setEnabled(true);
    }

    switch(mode){
    case PASSWORD:
    {
        qDebug() << "switch to password";

        authMode = mode;

        if(!enableBioAuth || !receiveBioPAM || useDoubleAuth) {
            ui->btnBioAuth->hide();
        }else{
            ui->btnBioAuth->show();
        }
	
        if(isHiddenSwitchButton)
            ui->btnBioAuth->hide();

        // if(enableBioAuth && useDoubleAuth){
        //     DeviceInfoPtr device = bioDevices.getDefaultDevice(getuid());
        //     if(device){
        //         widgetBioAuth->startAuth(getUid(userName), device);
        //     }
        // }
    }
        break;
    case BIOMETRIC:
    {
        qDebug() << "switch to biometric";
        if (m_deviceInfo) {
            if (!m_loginOptsWidget->findDeviceById(m_deviceInfo->device_id)
                || m_loginOptsWidget->isDeviceDisable(m_deviceInfo->device_id)) {
                m_deviceInfo = DeviceInfoPtr();
            }
        }
        if(authMode == PASSWORD) {
            emit accept(BIOMETRIC_IGNORE);
            return;
        }else if(!enableBioAuth){
            qDebug() << "It doesn't meet the condition for enabling biometric authentication, switch to password.";
            emit accept(BIOMETRIC_IGNORE);
            return;
        } else if(authMode == BIOMETRIC) {
            QString strDeviceName = m_loginOptsWidget->GetDefaultDevice(getuid());
            //如果默认设备为空的话，第一次不启动生物识别认证
            if(strDeviceName.isEmpty() && !m_deviceInfo)
            {
                qDebug() << "No default device";
                if(useFirstDevice == true){
                    m_deviceInfo = m_loginOptsWidget->getFirstDevInfo();
                } else {
                    emit accept(BIOMETRIC_IGNORE);
                    return;
                }
            }
            //第一次，获取默认设备的设备信息，之后使用的则是从设备选择窗口传出的设备信息
            if(!m_deviceInfo)
            {
                m_deviceInfo = m_loginOptsWidget->findDeviceByName(strDeviceName);
                if (!m_deviceInfo)
                    m_deviceInfo = m_loginOptsWidget->getFirstDevInfo();
            }
            if(!m_deviceInfo){
                emit accept(BIOMETRIC_IGNORE);
                return;
            }
            if(m_failMap.contains(uid) && m_failMap[uid].contains(m_deviceInfo->device_id)
                && m_failMap[uid][m_deviceInfo->device_id] >= maxFailedTimes){
                emit accept(BIOMETRIC_IGNORE);
                return;
            }
            startBioAuth();
            emit accept(BIOMETRIC_IGNORE);
            return;
        } else if(authMode == UNDEFINED){
            authMode = BIOMETRIC;

            if(enableBioAuth) {
                qDebug() << "enable biometric authenticaion";
                QString strDeviceName = m_loginOptsWidget->GetDefaultDevice(getuid());
                //如果默认设备为空的话，第一次不启动生物识别认证
                if(strDeviceName.isEmpty() && !m_deviceInfo)
                {
                    qDebug() << "No default device";
                    if(useFirstDevice == true){
                        m_deviceInfo = m_loginOptsWidget->getFirstDevInfo();
                    }else{
                        emit accept(BIOMETRIC_IGNORE);
                        return;
                    }
                }
                //第一次，获取默认设备的设备信息，之后使用的则是从设备选择窗口传出的设备信息
                if(!m_deviceInfo)
                {
                    m_deviceInfo = m_loginOptsWidget->findDeviceByName(strDeviceName);
                    if (!m_deviceInfo)
                        m_deviceInfo = m_loginOptsWidget->getFirstDevInfo();
                }
                if(!m_deviceInfo){
                    emit accept(BIOMETRIC_IGNORE);
                    return;
                }
                if(m_failMap.contains(uid) && m_failMap[uid].contains(m_deviceInfo->device_id)
                    && m_failMap[uid][m_deviceInfo->device_id] >= maxFailedTimes){
                    emit accept(BIOMETRIC_IGNORE);
                    return;
                }
                startBioAuth();
                emit accept(BIOMETRIC_IGNORE);
                return;
            } else {
                /* pass biometric's pam module if there are not available devices */
                qDebug() << "It doesn't meet the condition for enabling biometric authentication, switch to password.";
                emit accept(BIOMETRIC_IGNORE);
                return;
            }
        }
    }
        break;
    default:
        break;
    }
    switchWidget(mode);
}

/*** end of public memeber ***/


/*** private member ***/

uid_t MainWindow::getUid(const QString &userName)
{
    struct passwd *pwd = getpwnam(userName.toStdString().c_str());
    if(pwd == NULL) {
        qWarning() << "getpwnam error: " << strerror(errno);
        return -1;
    }
    return pwd->pw_uid;
}

void MainWindow::setDoubleAuth(bool val){
     useDoubleAuth = val;
}

void MainWindow::stopDoubleAuth()
{
//    if(useDoubleAuth && widgetBioAuth)
//        widgetBioAuth->stopAuth();
}

void MainWindow::switchWidget(Mode mode)
{
    ui->widgetPasswdAuth->hide();
    ui->btnAuth->hide();
    ui->btnAuth->setText(tr("Authenticate"));
    ui->btnAuth->adjustSize();
    ui->btnBioAuth->setText(tr("Biometric"));
    ui->btnBioAuth->adjustSize();
    ui->btnCancel->setText(tr("Cancel"));
    ui->btnCancel->adjustSize();
    ui->returnButton->setText(tr("Use password"));
    ui->returnButton->adjustSize();
    switch(mode){
    case PASSWORD:
    {
        setMinimumWidth(420);
        setMaximumWidth(420);
        if (m_deviceInfo && m_loginOptsWidget->findDeviceById(m_deviceInfo->device_id)) {
            switchLoginOptType(m_loginOptsWidget->convertDeviceType(m_deviceInfo->biotype));
        } else {
            switchLoginOptType(LOGINOPT_TYPE_PASSWORD);
        }
        if (!m_loginOptsWidget->isHidden()) {
            m_loginOptsWidget->adjustSize();
        }
        int height;
        if(fontSize = 10){
            height = 120 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                    + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                    + ui->btnAuth->height();
        } else if(fontSize = 11 ){
            height = 140 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                    + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                    + ui->btnAuth->height();
        } else if (fontSize = 12){
            height = 150 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                    + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                    + ui->btnAuth->height();
        } else if (fontSize = 13){
            height = 160 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                    + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                    + ui->btnAuth->height();
        } else if (fontSize = 14){
            height = 180 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                    + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                    + ui->btnAuth->height();
        } else if (fontSize = 15){
            height = 220 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                    + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                    + ui->btnAuth->height();
        }
        unsigned uOptsWidgetHeight = m_loginOptsWidget->height();
        if (m_loginOptsWidget->isHidden()) {
            uOptsWidgetHeight = 0;
            height -= 20 ;
        }
        ui->lblContent->adjustSize();
        ui->lblHeader->adjustSize();
        setMinimumHeight(height + uOptsWidgetHeight);
        setMaximumHeight(height + uOptsWidgetHeight);
        //m_loginOptsWidget->updateUIStatus();
        ui->btnBioAuth->setStyleSheet("QPushButton{font-size:14px;}QPushButton:hover{border:none;color:#3E6CE5;}QPushButton:pressed{border:none;}");
        ui->btnBioAuth->setFlat(true);
        ui->btnBioAuth->setText(tr("Biometric"));
        ui->btnBioAuth->setAttribute(Qt::WA_UnderMouse,false);
        ui->btnBioAuth->adjustSize();
        ui->widgetPasswdAuth->show();
        ui->lePassword->setFocus();
        ui->lePassword->setContextMenuPolicy(Qt::NoContextMenu); //禁用右键菜单
        ui->lePassword->setAttribute(Qt::WA_InputMethodEnabled, false);
        ui->lePassword->setEchoMode(QLineEdit::Password);
        ui->btnAuth->show();
        ui->btnCancel->show();
        //ui->lblContent->show();
        ui->returnButton->hide();
        ui->lblContent->hide();
    }
        break;

    case BIOMETRIC:
        setMinimumWidth(420);
        setMaximumWidth(420);
        if(bioDevices.count()<1||bioDevices.count()==1){
            setMinimumHeight(392+ui->cmbUsers->height()+ui->lblHeader->height());
            setMaximumHeight(392+ui->cmbUsers->height()+ui->lblHeader->height());
        }
        if(bioDevices.count()>1){
            setMinimumHeight(482+ui->cmbUsers->height()+ui->lblHeader->height());
            setMaximumHeight(482+ui->cmbUsers->height()+ui->lblHeader->height());
        }
        ui->btnCancel->hide();
        ui->lblContent->hide();
        ui->btnBioAuth->hide();
        ui->returnButton->show();
        ui->returnButton->setAttribute(Qt::WA_UnderMouse,false);
        ui->returnButton->setFlat(true);
        ui->returnButton->setStyleSheet("QPushButton{font-size:14px;}QPushButton:hover{border:none;color:#3E6CE5;}QPushButton:pressed{border:none;}");
        ui->returnButton->setText(tr("Use password"));
        ui->returnButton->adjustSize();
        break;
//    case DEVICES:
//        widgetBioAuth->show();

//        break;
    default:
        break;
    }
    adjustSize();
}

void MainWindow::unlock_countdown()
{
    int failed_count = 0;
    int time_left = 0;
    int deny = 0;
    int fail_time =0;
    int unlock_time = 0;
    pam_tally_unlock_time_left(getUid(userName),&failed_count, &time_left, &deny,&fail_time,&unlock_time);

    // qDebug() << "failed_count:" << failed_count << "time_left:" <<time_left <<"deny:"<<deny<<"fail_time:"<< fail_time<<"unlock_time:" << unlock_time;
    if(time_left >= 60)//请多少分钟后重试
    {
        int nMinuteleft = time_left/60;
        if (isLockingFlg == false){
            m_nCurLockMin = unlock_time/60;//获取当前需要锁定的分钟数
        }

        //如果当前设置的不是1min钟锁定，那么1min显示成2min，由2min直接跳到59s || 剩余分钟数小于当前设置的锁定时间，并且大于1min，自增+1
        if ((nMinuteleft == 1 && m_nCurLockMin != 1)  || (nMinuteleft > 1 && nMinuteleft < m_nCurLockMin))
        {
            nMinuteleft = nMinuteleft + 1;
        }
        setMessage(tr("Please try again in %1 minutes.").arg(nMinuteleft),TRUE);
        //ui->lblMessage->setToolTip(tr("Please try again in %1 minutes.").arg(nMinute));
        ui->lePassword->setText("");
        ui->lePassword->setDisabled(true);
        isLockingFlg = true;
        return ;
    }
    else if(time_left > 0 && time_left < 60)//请多少秒后重试
    {
        char ch[100]={0};
        setMessage(tr("Please try again in %1 seconds.").arg(time_left%60),TRUE);
        //ui->lblMessage->setToolTip(tr("Please try again in %1 seconds.").arg(time_left%60));
        ui->lePassword->setText("");
        ui->lePassword->setDisabled(true);
        isLockingFlg = true;
        return ;
    }
    else if (failed_count == 0xFFFF)//账号被永久锁定
    {
        ui->lblMessage->setText(tr("Account locked permanently."));
        ui->lblMessage->setToolTip(tr("Account locked permanently."));
        ui->lePassword->setText("");
        ui->lePassword->setDisabled(true);
        isLockingFlg = true;
        return ;
    }
    else
    {
        if(ui->lePassword){
            ui->lePassword->setDisabled(false);
            ui->lePassword->setFocus();
        }

        if (isLockingFlg) {
            //setMessage(tr("Authentication failed, please try again."),ERROR);
            setMessage("");
            isLockingFlg = false;
        }
        m_timer->stop();
    }
    return ;
}

void MainWindow::root_unlock_countdown()
{
    int failed_count = 0;
    int time_left = 0;
    int deny = 0;
    int fail_time =0;
    int unlock_time = 0;
    pam_tally_root_unlock_time_left(&failed_count, &time_left, &deny,&fail_time,&unlock_time);

    // qDebug() << "failed_count:" << failed_count << "time_left:" <<time_left <<"deny:"<<deny<<"fail_time:"<< fail_time<<"unlock_time:" << unlock_time;
    int nMinuteleft = time_left/60;
    if(time_left >= 60)//请多少分钟后重试
    {
        int nMinuteleft = time_left/60;
        if (isLockingFlg == false){
            m_nCurLockMin = unlock_time/60;//获取当前需要锁定的分钟数
        }

        //如果当前设置的不是1min钟锁定，那么1min显示成2min，由2min直接跳到59s || 剩余分钟数小于当前设置的锁定时间，并且大于1min，自增+1
        if ((nMinuteleft == 1 && m_nCurLockMin != 1)  || (nMinuteleft > 1 && nMinuteleft < m_nCurLockMin))
        {
            nMinuteleft = nMinuteleft + 1;
        }

        ui->lblMessage->setText(tr("Please try again in %1 minutes.").arg(nMinuteleft));
        ui->lblMessage->setToolTip(tr("Please try again in %1 minutes.").arg(nMinuteleft));
        ui->lePassword->setText("");
        ui->lePassword->setDisabled(true);
        isLockingFlg = true;
        return ;
    }
    else if(time_left > 0 && time_left < 60)//请多少秒后重试
    {
        char ch[100]={0};
        ui->lblMessage->setText(tr("Please try again in %1 seconds.").arg(time_left%60));
        ui->lblMessage->setToolTip(tr("Please try again in %1 seconds.").arg(time_left%60));
        ui->lePassword->setText("");
        ui->lePassword->setDisabled(true);
        isLockingFlg = true;
        return ;
    }
    else if (failed_count == 0xFFFF)//账号被永久锁定
    {
        ui->lblMessage->setText(tr("Account locked permanently."));
        ui->lblMessage->setToolTip(tr("Account locked permanently."));
        ui->lePassword->setText("");
        ui->lePassword->setDisabled(true);
        isLockingFlg = true;
        return ;
    }
    else
    {
        if(ui->lePassword){
            ui->lePassword->setDisabled(false);
            ui->lePassword->setFocus();
        }

        if (isLockingFlg)
        {
            //setMessage(tr("Authentication failed, please try again."),ERROR);
            setMessage("");
            isLockingFlg = false;
        }
            
        m_timer->stop();
    }
    return ;
}

void MainWindow::switchLoginOptType(unsigned uLoginOptType)
{
    switch(uLoginOptType) {
    case LOGINOPT_TYPE_PASSWORD:
    {
        m_loginOptsWidget->hide();
    }
        break;
    case LOGINOPT_TYPE_FACE:
    case LOGINOPT_TYPE_FINGERPRINT:
    case LOGINOPT_TYPE_IRIS:
    case LOGINOPT_TYPE_VOICEPRINT:
    case LOGINOPT_TYPE_FINGERVEIN:
    case LOGINOPT_TYPE_QRCODE:
    {
        //m_loginOptsWidget->show();
        // 延迟检查错误状态
        m_isNetworkErr = false;
        QTimer::singleShot(500, this, [&,this](){
            if (!this->m_isNetworkErr) {
                m_loginOptsWidget->setQRCodeMsg("");
            }
        });
    }
        break;
    default:
        return;
    }
    qDebug()<<"CurOptType:"<<uLoginOptType;
    if(m_deviceInfo && m_failMap.contains(getUid(userName))
        && m_failMap[getUid(userName)].contains(m_deviceInfo->device_id)
        && m_failMap[getUid(userName)][m_deviceInfo->device_id] >= maxFailedTimes){
        if (m_deviceInfo->biotype == BIOTYPE_FACE) {
            QImage imgFailed;
            m_loginOptsWidget->setFaceImg(imgFailed, 1);
        }
        if (m_deviceInfo->biotype == REMOTE_QRCODE_TYPE) {
            setLoginTypeTip(tr("Failed to verify %1, please enter password to unlock").arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype)));
        } else {
            setLoginTypeTip(tr("Unable to verify %1, please enter password to unlock").arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype)));
        }
        m_loginOptsWidget->setDeviceDisable(m_deviceInfo->device_id, true);
    } else {
        if (uLoginOptType != m_uCurLoginOptType || (m_deviceInfo && m_deviceInfo->device_id != m_nLastDeviceId)) {
            switch(uLoginOptType) {
            case LOGINOPT_TYPE_PASSWORD:
            {
                setLoginTypeTip("");
                //setMessage("",TRUE);
            }
                break;
            case LOGINOPT_TYPE_FACE:
            {
                setLoginTypeTip(tr("Verify face recognition or enter password to unlock"));
            }
                break;
            case LOGINOPT_TYPE_FINGERPRINT:
            {
                setLoginTypeTip(tr("Press fingerprint or enter password to unlock"));
            }
                break;
            case LOGINOPT_TYPE_VOICEPRINT:
            {
                setLoginTypeTip(tr("Verify voiceprint or enter password to unlock"));
            }
                break;
            case LOGINOPT_TYPE_FINGERVEIN:
            {
                setLoginTypeTip(tr("Verify finger vein or enter password to unlock"));
            }
                break;
            case LOGINOPT_TYPE_IRIS:
            {
                setLoginTypeTip(tr("Verify iris or enter password to unlock"));
            }
                break;
            case LOGINOPT_TYPE_QRCODE:
            {
                setLoginTypeTip(tr("Use the bound wechat scanning code or enter the password to unlock"));
            }
                break;
            default:
                return;
            }
        }
    }
    if (m_deviceInfo) {
        m_nLastDeviceId = m_deviceInfo->device_id;
    } else {
        m_nLastDeviceId = -1;
    }
    m_uCurLoginOptType = uLoginOptType;
}

void MainWindow::setLoginTypeTip(QString strLoginTypeTip)
{
    m_strLoginTypeTip = strLoginTypeTip;
    if (m_strLoginTypeTip.isEmpty()) {
        m_labelTip->hide();
    } else {
        QFontMetrics font(m_labelTip->font());
        //返回字符串末尾带省略号的字符串
        QString strDisplay = font.elidedText(m_strLoginTypeTip, Qt::ElideRight, m_labelTip->width()-8);
        QPalette pe;
        pe.setColor(QPalette::WindowText,Qt::blue);
        m_labelTip->setPalette(pe);
        m_labelTip->setText(strDisplay);
        m_labelTip->setToolTip(m_strLoginTypeTip);
        m_labelTip->show();
    }
}

void MainWindow::startBioAuthDelay()
{
    m_loginOptsWidget->startAuth(m_deviceInfo, getUid(userName));
    if (m_deviceInfo) {
        switchLoginOptType(m_loginOptsWidget->convertDeviceType(m_deviceInfo->biotype));
    } else {
        switchLoginOptType(LOGINOPT_TYPE_PASSWORD);
    }
    m_bioTimer->stop();
}

void MainWindow::startBioAuth(unsigned uTimeout)
{
    m_loginOptsWidget->stopAuth();
    if(!m_bioTimer){
        m_bioTimer = new QTimer(this);
        connect(m_bioTimer, SIGNAL(timeout()), this, SLOT(startBioAuthDelay()));
    }
    ui->lblMessage->clear();
    ui->lblMessage->setToolTip("");
    m_bioTimer->start(uTimeout);
}

void MainWindow::onUpdateBioAuthMsg(QString strMsg)
{
    setMessage(strMsg, TRUE);
}

void MainWindow::onUpdateWndSize(unsigned uLoginOptType, unsigned uLoginOptSize)
{
    ui->lblContent->hide();
    if (!m_loginOptsWidget->isHidden()) {
        m_loginOptsWidget->adjustSize();
    }
    unsigned uOptsWidgetHeight = m_loginOptsWidget->height();
    if (m_loginOptsWidget->isHidden() ||
        (uLoginOptSize == 1 && uLoginOptType != LOGINOPT_TYPE_QRCODE && uLoginOptType != LOGINOPT_TYPE_FACE)) {
        uOptsWidgetHeight = 0;
    }
    ui->lblHeader->adjustSize();
    if(uLoginOptType == LOGINOPT_TYPE_QRCODE && uLoginOptType == LOGINOPT_TYPE_FACE){
            uOptsWidgetHeight = m_loginOptsWidget->height() + 20;
    }
    else if(uLoginOptType == LOGINOPT_TYPE_FINGERPRINT){
            uOptsWidgetHeight = m_loginOptsWidget->height() + 10 ;
    }
//    ui->lblContent->adjustSize();
    ui->lblHeader->adjustSize();
    int height;
    if(fontSize = 10){
        height = 120 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                + ui->btnAuth->height();
    } else if(fontSize = 11 ){
        height = 140 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                + ui->btnAuth->height();
    } else if (fontSize = 12){
        height = 150 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                + ui->btnAuth->height();
    } else if (fontSize = 13){
        height = 160 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                + ui->btnAuth->height();
    } else if (fontSize = 14){
        height = 180 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                + ui->btnAuth->height();
    } else if (fontSize = 15){
        height = 220 + ui->lblHeader->height() /*+ ui->lblContent->height()*/
                + ui->cmbUsers->height() + ui->lePassword->height() + ui->lblMessage->height()
                + ui->btnAuth->height();
    }
    if (m_loginOptsWidget->isHidden()) {
        height -= 20 ;
    }
    setMinimumHeight(height + uOptsWidgetHeight);
    setMaximumHeight(height + uOptsWidgetHeight);
}

/*** end of private member ***/
